package com.ssmr.demo.service;

import com.ssmr.demo.entity.TProduct;
import com.ssmr.demo.entity.TPurchaseRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;


@Service
@RabbitListener(queues = "ssmr_queue")
public class RabbitmqConsumerServiceImpl implements RabbitmqConsumerService, ApplicationContextAware {

    @Autowired
    private AmqpTemplate amqpTemplate;
    @Autowired
    private TPurchaseRecordService tPurchaseRecordService;
    @Autowired
    private TProductService tProductService;
    @Autowired
    private RedisTemplate redisTemplate;
    private ApplicationContext applicationContext = null;

    private static final String SSMR_EXCHANGE = "ssmr_exchange";
    private static final String SSMR_QUEUE = "ssmr_queue";
    private static final String SSMR_ROUTING_KEY = "ssmr_routing_key";
    private static final String SECKILL_PREFIX = "seckill_";
    private static Logger logger = LoggerFactory.getLogger(RabbitmqConsumerServiceImpl.class);


    /*这里应该不用@Async吧，正常项目里，消费者和生产者肯定不在一个项目部署的*/
    @Override
    @RabbitHandler
    /* Failed to send reply with payload 'InvocationResult
    * 监听函数不能设置返回值*/
    public void consumePurchaseRecordMessage(TPurchaseRecord tPurchaseRecord) {
        tPurchaseRecordService.insert(tPurchaseRecord);
        logger.info("Rabbitmq consumer thread: " + Thread.currentThread().getName());
        logger.info(tPurchaseRecord.toString());
        /*解决自调用问题*/
        RabbitmqConsumerService bean = applicationContext.getBean(RabbitmqConsumerService.class);
        bean.updateProductAsync(tPurchaseRecord);
    }

    /*这个异步好像有数据一致性问题？待查*/
    @Async
    @Override
    /*这里直接加事务@Transactional不起作用，因为是自调用，可以写到别的service里，或者从IOC容器拿出代理对象*/
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void updateProductAsync(TPurchaseRecord tPurchaseRecord) {
        /*暂时不能这样写，因为这个缓存是从redisCacheManager得到的；秒杀时，之前插入的缓存是用redisTemplate插入的。
        TProduct tProduct = tProductService.selectByPrimaryKey(tPurchaseRecord.getProductId());*/
        ArrayList<String> arrayList = new ArrayList<>();
        arrayList.add("idtProduct");
        arrayList.add("product_name");
        arrayList.add("stock");
        arrayList.add("price");
        arrayList.add("version");
        List list = redisTemplate.opsForHash().multiGet(SECKILL_PREFIX + String.valueOf(tPurchaseRecord.getProductId()), arrayList);
        /*这个可能是脏数据，不过反正不用来输出*/
        TProduct tProduct = tProductService.selectByPrimaryKey(tPurchaseRecord.getProductId());
        tProduct.setStock(Integer.parseInt((String) list.get(2)));
        tProduct.setVersion(Integer.parseInt((String) list.get(4)));
        /*这个是通过redisCacheManager缓存的，默认mbg提供的update没缓存*/
        TProduct tProduct1 = tProductService.updateByPrimaryKeyAndReturn(tProduct);
        logger.info("Rabbitmq consumer thread, update method: " + Thread.currentThread().getName());
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
